package org.lanyu.springainovel.novel.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.lanyu.springainovel.common.config.ChatModelManager;
import org.lanyu.springainovel.common.entity.AiModel;
import org.lanyu.springainovel.common.service.AiModelService;
import org.lanyu.springainovel.chat.vo.ImagePromptVO;
import org.lanyu.springainovel.novel.entity.Book;
import org.lanyu.springainovel.novel.entity.BookOutline;
import org.lanyu.springainovel.novel.entity.ChapterContent;
import org.lanyu.springainovel.novel.mapper.BookMapper;
import org.lanyu.springainovel.novel.service.BookService;
import org.lanyu.springainovel.novel.service.NovelOutlineService;
import org.lanyu.springainovel.novel.service.ChapterContentService;
import org.lanyu.springainovel.chat.service.PromptTemplateService;
import org.lanyu.springainovel.common.entity.MyPromptTemplate;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.image.*;
import org.springframework.ai.openai.OpenAiImageOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;

/**
 * 书籍服务实现类
 */
@Slf4j
@Service
public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements BookService {

    @Autowired
    private NovelOutlineService novelOutlineService;
    
    @Autowired
    private ChapterContentService chapterContentService;
    
    @Autowired
    private ChatModelManager chatModelManager;
    
    @Autowired
    private AiModelService aiModelService;
    
    @Autowired
    private PromptTemplateService promptTemplateService;
    
    @Value("${ai.file.upload-dir}")
    private String uploadDir;

    @Override
    public List<Book> getBooksByUserId(Long userId) {
        QueryWrapper<Book> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.orderByDesc("update_time");
        return this.list(queryWrapper);
    }

    @Override
    public Book createBook(Book book) {
        book.setCreateTime(LocalDateTime.now());
        book.setUpdateTime(LocalDateTime.now());
        // 默认状态为草稿
        if (book.getStatus() == null) {
            book.setStatus(0);
        }
        this.save(book);
        return book;
    }

    @Override
    public Book updateBook(Book book) {
        book.setUpdateTime(LocalDateTime.now());
        this.updateById(book);
        return book;
    }

    @Override
    public Book getBookById(Long id) {
        return this.getById(id);
    }
    
    @Override
    public String saveImageToLocal(String imageUrl, Long bookId) {
        try {
            log.info("开始保存图片到本地，图片URL: {}, 书籍ID: {}, 上传目录: {}", imageUrl, bookId, uploadDir);
            
            // 创建书籍封面目录
            String coverDir = uploadDir + "novel/" + bookId + "/cover/";
            Path coverDirPath = Paths.get(coverDir);
            log.info("创建封面目录: {}", coverDir);
            
            if (!Files.exists(coverDirPath)) {
                Files.createDirectories(coverDirPath);
                log.info("封面目录创建成功");
            }
            
            // 生成唯一文件名
            String fileName = UUID.randomUUID().toString() + ".jpg";
            String localPath = coverDir + fileName;
            log.info("本地文件路径: {}", localPath);
            
            // 下载图片并保存到本地
            log.info("开始下载图片");
            // 处理URL中的特殊字符，使用URLDecoder解码
            String decodedUrl = java.net.URLDecoder.decode(imageUrl, "UTF-8");
            log.info("解码后的URL: {}", decodedUrl);
            
            URL url = new URL(decodedUrl);
            try (InputStream in = url.openStream();
                 FileOutputStream out = new FileOutputStream(localPath)) {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
            }
            log.info("图片下载并保存成功");
            
            // 返回相对路径，用于数据库存储
            String relativePath = "uploads/novel/" + bookId + "/cover/" + fileName;
            log.info("返回相对路径: {}", relativePath);
            return relativePath;
        } catch (Exception e) {
            log.error("保存图片到本地失败，图片URL: {}, 书籍ID: {}, 上传目录: {}", imageUrl, bookId, uploadDir, e);
            throw new RuntimeException("保存图片到本地失败: " + e.getMessage());
        }
    }
    

    
    @Override
    public boolean deleteBookDirectory(Long bookId) {
        try {
            // 构建书籍目录路径
            String bookDirPath = uploadDir + "novel/" + bookId;
            Path bookDir = Paths.get(bookDirPath);
            
            // 如果目录存在，则删除
            if (Files.exists(bookDir)) {
                log.info("开始删除书籍目录: {}", bookDirPath);
                
                // 递归删除目录及其内容
                Files.walk(bookDir)
                    .sorted(Comparator.reverseOrder())
                    .map(Path::toFile)
                    .forEach(File::delete);
                
                log.info("书籍目录删除成功: {}", bookDirPath);
                return true;
            } else {
                log.info("书籍目录不存在，无需删除: {}", bookDirPath);
                return true;
            }
        } catch (Exception e) {
            log.error("删除书籍目录失败，书籍ID: {}, 目录路径: {}", bookId, uploadDir + "novel/" + bookId, e);
            return false;
        }
    }

    /**
     * 创建书籍封面
     * @param imagePromptVO 图片生成请求参数
     * @return
     */
    @Override
    public String createBookCover(ImagePromptVO imagePromptVO) {
        try {
            // 通过模型ID查找模型配置
            AiModel modelConfig = aiModelService.findById(imagePromptVO.getModelId());
            if (modelConfig == null) {
                throw new RuntimeException("未找到指定模型ID: " + imagePromptVO.getModelId());
            }
            
            // 生成封面提示词
            String imagePromptMessage = generateImagePrompt(imagePromptVO);
            
            // 设置书籍封面尺寸参数 - 固定生成一张图，尺寸为书籍封面标准尺寸
            ImageOptions options = OpenAiImageOptions.builder()
                    .model(modelConfig.getName())
                    .N(1)  // 固定生成一张图
                    .width(200)  // 书籍封面宽度
                    .height(280)  // 书籍封面高度
                    .build();
            
            ImageMessage imageMessage = new ImageMessage(imagePromptMessage, imagePromptVO.getWeight());
            List<ImageMessage> messageList = new ArrayList<>();
            messageList.add(imageMessage);
            ImagePrompt imagePrompt = new ImagePrompt(messageList, options);
            
            // 通过ChatModelManager获取生图模型
            ImageModel imageModel = chatModelManager.getOrCreateImageModel(modelConfig);
            ImageResponse imageResponse = imageModel.call(imagePrompt);
            
            // 获取生成的图片URL（只返回一个字符串，不是列表）
            String imageUrl = imageResponse.getResult().getOutput().getUrl();
            
            return imageUrl;
        } catch (Exception e) {
            log.error("创建书籍封面失败", e);
            throw new RuntimeException("创建书籍封面失败: " + e.getMessage());
        }
    }
    
    /**
     * 生成封面提示词
     * @param imagePromptVO 图片生成请求参数
     * @return 生成的封面提示词
     */
    private String generateImagePrompt(ImagePromptVO imagePromptVO) {
        try {
            // 如果没有提供聊天模型ID，直接使用原始消息
            if (imagePromptVO.getChatModelId() == null) {
                return imagePromptVO.getMessage();
            }
            
            // 获取聊天模型配置
            AiModel chatModelConfig = aiModelService.findById(imagePromptVO.getChatModelId());
            if (chatModelConfig == null) {
                log.warn("未找到指定的聊天模型ID: {}, 使用原始消息", imagePromptVO.getChatModelId());
                return imagePromptVO.getMessage();
            }
            
            // 获取聊天模型
            ChatModel chatModel = chatModelManager.getOrCreateChatModel(chatModelConfig);
            
            // 创建ChatClient
            ChatClient chatClient = ChatClient.builder(chatModel).build();
            
            // 构建系统提示词
            String systemPrompt = "你是一个专业的书籍封面设计师。请根据用户提供的书籍信息，生成一个适合用于AI绘画的详细封面描述。描述应该包括：1.画面主体内容 2.风格和色调 3.构图和布局 4.重要细节。请直接输出封面描述，不要包含其他解释。";
            
            // 如果提供了系统提示词模板ID，使用模板内容
            if (imagePromptVO.getSysTemplateId() != null) {
                MyPromptTemplate template = promptTemplateService.getTemplateById(imagePromptVO.getSysTemplateId());
                if (template != null && template.getContent() != null && !template.getContent().isEmpty()) {
                    systemPrompt = template.getContent();
                    // 增加模板使用次数
                    promptTemplateService.incrementUsageCount(imagePromptVO.getSysTemplateId());
                }
            }
            
            // 调用聊天模型生成封面提示词
            String userMessage = "请为以下书籍生成一个封面描述：" + imagePromptVO.getMessage();
            Prompt prompt = new Prompt(List.of(
                new org.springframework.ai.chat.messages.SystemMessage(systemPrompt),
                new UserMessage(userMessage)
            ));

            String generatedPrompt = chatClient.prompt(prompt).call().content();
            
            // 如果生成失败或为空，使用原始消息
            if (generatedPrompt == null || generatedPrompt.trim().isEmpty()) {
                log.warn("聊天模型生成的提示词为空，使用原始消息");
                return imagePromptVO.getMessage();
            }
            
            log.info("使用聊天模型生成封面提示词成功，原始消息：{}，生成提示词：{}", imagePromptVO.getMessage(), generatedPrompt);
            return generatedPrompt;
            
        } catch (Exception e) {
            log.error("使用聊天模型生成封面提示词失败，使用原始消息", e);
            return imagePromptVO.getMessage();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(Long id) {
        try {
            log.info("开始级联删除书籍及其相关数据，书籍ID: {}", id);
            
            // 1. 删除书籍大纲
            QueryWrapper<BookOutline> outlineWrapper = new QueryWrapper<>();
            outlineWrapper.eq("book_id", id);
            boolean outlineDeleted = novelOutlineService.remove(outlineWrapper);
            log.info("删除书籍大纲结果: {}, 书籍ID: {}", outlineDeleted, id);
            
            // 2. 删除章节内容
            QueryWrapper<ChapterContent> chapterWrapper = new QueryWrapper<>();
            chapterWrapper.eq("book_id", id);
            boolean chapterDeleted = chapterContentService.remove(chapterWrapper);
            log.info("删除章节内容结果: {}, 书籍ID: {}", chapterDeleted, id);
            
            // 3. 删除书籍
            boolean bookDeleted = super.removeById(id);
            log.info("删除书籍结果: {}, 书籍ID: {}", bookDeleted, id);
            
            if (bookDeleted) {
                log.info("级联删除成功，书籍ID: {}", id);
            } else {
                log.warn("书籍删除失败，书籍ID: {}", id);
            }
            
            return bookDeleted;
        } catch (Exception e) {
            log.error("级联删除失败，书籍ID: {}", id, e);
            throw e;
        }
    }
}